using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Sedna.Core.Controller;
using Sedna.Core.Controller.Common;

namespace Sedna.Core.Security
{
    public class PageLoader : AbstractAction
    {
        /// <summary>
        /// Defines what action should be executed
        /// </summary>
        protected IActionResolver actionResolver;
        
        /// <summary>
        /// List of actions that can be executed on a page
        /// </summary>
        protected IList actions;

        protected String postBackConditionFailedStatus = "none";

        # region Properties

        public IActionResolver ActionResolver
        {
            set { actionResolver = value; }
        }

        public IList Actions
        {
            set { actions = value; }
        }

        public string PostBackConditionFailedStatus
        {
            set { postBackConditionFailedStatus = value; }
        }

        # endregion

        public override IActionResult Execute(IExecutionContext executionContext)
        {
            switch (postBackCondition)
            {
                case PostBackCondition.NotPostBack:
                    {
                        if (executionContext.IsPostBack)
                            return CreateResult(postBackConditionFailedStatus);
                        
                        break;
                    }
                case PostBackCondition.PostBack:
                    {
                        if (!executionContext.IsPostBack)
                            return CreateResult(postBackConditionFailedStatus);

                        break;
                    }    
            }
            
            IActionResult actionResult = null;

            if (actions != null)
            {
                String actionName = actionResolver.Resolve(executionContext);

                ISecureAction action = FindAction(actionName.ToLower());

                if (action == null)
                {
                    ActionNotFoundNotification(actionName, executionContext);

                    // override the method above if you don't wanna get exception
                    throw new SednaException(SednaExceptionCodes.ActionNotFound);
                }

                if (!action.CanExecute(principalWrapper, executionContext))
                {
                    ActionExecutionForbiddenNotification(action, executionContext);

                    // override the method above if you don't wanna get exception
                    throw new SednaException(SednaExceptionCodes.ActionExecutionForbidden);
                }

                actionResult = action.Execute(executionContext);

                action.ApplyPolicy(principalWrapper, executionContext);
            }

            actionResult = ExecuteCustom(executionContext, actionResult);

            return actionResult;
        }
        
        
        /// <summary>
        /// By default this method does nothing, but its behaviour
        /// can be overridden in childs in order to return special status
        /// or redirect to another page with certain message.
        /// </summary>
        protected virtual void ActionNotFoundNotification(String actionName, IExecutionContext executionContext)
        {
        }

        /// <summary>
        /// By default this method does nothing, but its behaviour
        /// can be overridden in childs in order to return special status
        /// or redirect to another page with certain message.
        /// </summary>
        protected virtual void ActionExecutionForbiddenNotification(ISecureAction action, IExecutionContext executionContext)
        {
        }

        /// <summary>
        /// By default this method does nothing, but its behaviour
        /// can be overridden in childs in order to load extra data or
        /// set custom view & edit policy for page's controls
        /// </summary>
        public virtual IActionResult ExecuteCustom(IExecutionContext executionContext, IActionResult baseActionResult)
        {
            return baseActionResult;
        }

        private ISecureAction FindAction(String actionName)
        {
            if (actions == null)
                return null;

            foreach (ISecureAction action in actions)
            {
                if (action.Name.ToLower().Equals(actionName))
                    return action;
            }
            
            return null;
        }
    }
}
